#ifndef _POLL_HPP_
#define _POLL_HPP_

#include <iostream>
#include <string>
#include <poll.h>
#include "log.hpp"
#include "Sock.hpp"

using std::cout;
using std::endl;
using std::string;

#define FD_NOME -1

class PollServer
{
public:
    static const int nfds = 100;

    PollServer(const uint16_t& port = 8080)
        :_port(port)
        ,_nfds(nfds)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(NORMAL, "%s", "create base socket success");

        _fds = new struct pollfd[_nfds];
        for (int i = 0; i < _nfds; i++)
        {
            _fds[i].fd = FD_NOME;
            _fds[i].events = _fds[i].revents = 0;
        }

        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN;   // 这里POLLIN为读事件  POLLOUT为写事件  POLLERR为异常事件 如果需要同时关注多个事件, 用 | 连接可以
        _timeout = 1000;
    }

    void start()
    {
        while (true)
        {
            int n = poll(_fds, _nfds, _timeout);
            switch(n)
            {
            case 0:
                logMessage(NORMAL, "%s", "time out");
                break;
            case -1:
                logMessage(WARNING, "poll error, %d: %s", errno, strerror(errno));
            default:
                // 这里有文件描述符就绪的
                logMessage(NORMAL, "get a new link...");
                HandlerEvent();
                break;
            }
        }
    }

    ~PollServer()
    {
        if (_listensock >= 0)   close(_listensock);
        if (_fds)    delete[] _fds;
    }
private:
    void HandlerEvent()
    {
        for (int i = 0; i < _nfds; i++)
        {
            if (_fds[i].fd == FD_NOME)
                continue;
            if (_fds[i].revents && POLLIN)
            {
                if (_fds[i].fd == _listensock)
                {
                    Accepter();
                }
                else
                {
                    Recver(i);
                }
            }
        }
    }

    void Accepter()
    {
        string client_ip;
        uint16_t client_port = 0;

        // 连接套机子  此时不会阻塞的
        int sock = Sock::Accpet(_listensock, &client_port, &client_ip);
        if (sock < 0)
        {
            logMessage(ERROR, "accept error: %d : %s", errno, strerror(errno));
            return;
        }
        logMessage(DEBUG, "accept success");

        // 把sock放入数组中
        int pos = 1;
        for (; pos < _nfds; pos++)
        {
            if (_fds[pos].fd == FD_NOME)
                break;
        }
        if (pos == _nfds)
        {
            logMessage(WARNING, "%s: %d", "poll server alreadly full, close: %d", sock);
            close(sock);
        }
        else
        {
            _fds[pos].fd = sock;
            _fds[pos].events = POLLIN;
        }
    }

    void Recver(int pos)
    {
        logMessage(NORMAL, "message in Get IO event: %d", _fds[pos]);

        char buffer[1024];
        int n = recv(_fds[pos].fd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(NORMAL, "client[%d]# %s", _fds[pos].fd, buffer);
        }
        else if (n == 0)
        {
            logMessage(NORMAL, "client[%d] quit, me too ...", _fds[pos].fd);
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NOME;
            _fds[pos].events = 0;
        }
        else
        {
            logMessage(ERROR, "%d sock recv error, %d: %s", _fds[pos].fd, errno, strerror(errno));
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NOME;
            _fds[pos].events = 0;
        }
    }

private:
    uint16_t _port;
    int _listensock;
    struct pollfd* _fds;  // poll的三个参数,全部设成类内成员
    int _nfds;
    int _timeout;
};


#endif